<template>
    <a-scrollable>
        <a-scrollable-h>
            <div
                class="a-table c-w-100 c-b"
                :class="[
                    `color-${myColor}`,
                    `size-${mySize}`,
                    { sharp: mySharp },
                    { disabled: myDisabled },
                    { 'un-top': scrollDistanceTop > 0 },
                    { 'un-left': scrollDistanceLeft > 0 },
                    { 'un-right': scrollDistanceRight > 0 },
                ]"
                :style="tableContainerStyle"
            >
                <table :style="tableStyle" ref="table">
                    <thead
                        :class="[
                            {
                                'sticky-top': !!maxHeight,
                            },
                        ]"
                    >
                        <tr>
                            <template v-if="selectable">
                                <th
                                    v-if="isMultiSelect"
                                    @click="toggleSelectAll"
                                    class="select-cell selectable"
                                    :class="[
                                        {
                                            'sticky-left': fixLeft,
                                        },
                                    ]"
                                    :rowspan="`${headerRows.length}`"
                                    :style="{
                                        width: this.actionWidth + 'px',
                                        left: this.selectCellLeft,
                                    }"
                                >
                                    <span
                                        class="fa fa-fw fa-square-o"
                                        v-show="!anySelected"
                                    ></span>
                                    <span
                                        class="fa fa-fw fa-minus-square-o"
                                        v-show="anySelected && !allSelected"
                                    ></span>
                                    <span
                                        class="fa fa-fw fa-check-square-o"
                                        v-show="allSelected"
                                    ></span>
                                </th>
                                <th
                                    v-else
                                    class="select-cell"
                                    :class="[
                                        {
                                            'sticky-left': fixLeft,
                                        },
                                    ]"
                                    :rowspan="`${headerRows.length}`"
                                    :style="{
                                        width: this.actionWidth + 'px',
                                        left: this.selectCellLeft,
                                    }"
                                ></th>
                            </template>
                            <template v-if="expandable">
                                <th
                                    v-if="isMultiExpand"
                                    @click="toggleExpandAll"
                                    class="expand-cell expandable"
                                    :class="[
                                        {
                                            'sticky-left': fixLeft,
                                        },
                                    ]"
                                    :rowspan="`${headerRows.length}`"
                                    :style="{
                                        width: this.actionWidth + 'px',
                                        left: this.expandCellLeft,
                                    }"
                                >
                                    <span
                                        class="fa fa-fw fa-angle-double-right"
                                        v-show="!anyExpand"
                                    ></span>
                                    <span
                                        class="fa fa-fw fa-minus-square-o"
                                        v-show="anyExpand && !allExpand"
                                    ></span>
                                    <span
                                        class="fa fa-fw fa-angle-double-down"
                                        v-show="allExpand"
                                    ></span>
                                </th>
                                <th
                                    v-else
                                    class="expand-cell"
                                    :class="[
                                        {
                                            'sticky-left': fixLeft,
                                        },
                                    ]"
                                    :rowspan="`${headerRows.length}`"
                                    :style="{
                                        width: this.actionWidth + 'px',
                                        left: this.expandCellLeft,
                                    }"
                                ></th>
                            </template>
                            <th
                                v-if="draggable"
                                class="drag-cell"
                                :class="[
                                    {
                                        'sticky-left': fixLeft,
                                    },
                                ]"
                                :rowspan="`${headerRows.length}`"
                                :style="{
                                    width: this.actionWidth + 'px',
                                    left: this.dragCellLeft,
                                }"
                            ></th>
                            <th
                                v-for="header in firstHeaderRow"
                                :width="
                                    headerRows.length == 1
                                        ? `${
                                              (getHeaderWidthFunc(header.item) /
                                                  headerTotalWidth) *
                                              100
                                          }%`
                                        : 'unset'
                                "
                                :rowspan="`${header.rowSpan}`"
                                :colspan="`${header.colSpan}`"
                                class="header-cell normal-cell"
                                :class="[
                                    {
                                        'right-cell': rightHeaderSet.has(
                                            header.item
                                        ),
                                        'sticky-left':
                                            fixLeft &&
                                            leftHeaderSet.has(header.item),
                                        'sticky-right':
                                            fixRight &&
                                            rightHeaderSet.has(header.item),
                                    },
                                ]"
                                :style="{
                                    left: this.normalSellLeft,
                                }"
                            >
                                <slot
                                    :name="`header-${getHeaderNameFunc(
                                        header.item
                                    )}`"
                                    :header="header.item"
                                    >{{ getHeaderTextFunc(header.item) }}</slot
                                >
                            </th>
                        </tr>
                        <tr v-for="(row, i) in restHeaderRows">
                            <th
                                v-for="header in row"
                                :width="
                                    i == restHeaderRows.length - 1
                                        ? `${
                                              (getHeaderWidthFunc(header.item) /
                                                  headerTotalWidth) *
                                              100
                                          }%`
                                        : 'unset'
                                "
                                :rowspan="`${header.rowSpan}`"
                                :colspan="`${header.colSpan}`"
                                :class="[
                                    {
                                        'right-cell': rightHeaderSet.has(
                                            header.item
                                        ),
                                        'sticky-left':
                                            fixLeft &&
                                            leftHeaderSet.has(header.item),
                                        'sticky-right':
                                            fixRight &&
                                            rightHeaderSet.has(header.item),
                                    },
                                ]"
                            >
                                <slot
                                    :name="`header-${getHeaderNameFunc(
                                        header.item
                                    )}`"
                                    :header="header.item"
                                    >{{ getHeaderTextFunc(header.item) }}</slot
                                >
                            </th>
                        </tr>
                    </thead>
                    <tbody>
                        <template
                            v-for="(data, dataIndex) in dataList"
                            :key="getKeyFunc(data)"
                        >
                            <tr
                                class="data-row"
                                :class="[
                                    {
                                        seleced: isItemSelected(data),
                                        dragging: dataIndex == draggingIndex,
                                        'one-of-us-dragging': draggingIndex != null
                                    },
                                    dataIndex == draggingIndex
                                        ? `c-shadow-${mySize}`
                                        : '',
                                ]"
                            >
                                <template v-if="selectable">
                                    <td
                                        v-if="getCanBeSelectedFunc(data)"
                                        @click="toggleSelectItem(data)"
                                        class="select-cell selectable"
                                        :class="[{ 'sticky-left': fixLeft }]"
                                        :style="{
                                            width: this.actionWidth + 'px',
                                            left: this.selectCellLeft,
                                        }"
                                    >
                                        <template v-if="isMultiSelect">
                                            <span
                                                v-if="isItemSelected(data)"
                                                class="fa fa-fw fa-check-square-o"
                                            ></span>
                                            <span
                                                v-else
                                                class="fa fa-fw fa-square-o"
                                            ></span>
                                        </template>
                                        <template v-else>
                                            <span
                                                v-if="isItemSelected(data)"
                                                class="fa fa-fw fa-circle"
                                            ></span>
                                            <span
                                                v-else
                                                class="fa fa-fw fa-circle-o"
                                            ></span>
                                        </template>
                                    </td>
                                    <td
                                        v-else
                                        class="select-cell"
                                        :class="[{ 'sticky-left': fixLeft }]"
                                        :style="{
                                            width: this.actionWidth + 'px',
                                            left: this.selectCellLeft,
                                        }"
                                    ></td>
                                </template>
                                <td
                                    v-if="expandable"
                                    class="expand-cell expandable"
                                    :class="[
                                        {
                                            'sticky-left': fixLeft,
                                        },
                                    ]"
                                    :style="{
                                        width: this.actionWidth + 'px',
                                        left: this.expandCellLeft,
                                    }"
                                    @click="toggleExpandItem(data)"
                                >
                                    <span
                                        v-if="isItemExpand(data)"
                                        class="fa fa-fw fa-angle-down"
                                    ></span>
                                    <span
                                        v-else
                                        class="fa fa-fw fa-angle-right"
                                    ></span>
                                </td>
                                <td
                                    v-if="draggable"
                                    class="drag-cell draggable"
                                    :class="[
                                        {
                                            'sticky-left': fixLeft,
                                        },
                                    ]"
                                    :style="{
                                        width: this.actionWidth + 'px',
                                        left: this.dragCellLeft,
                                    }"
                                    @mousedown.prevent="
                                        dragStart(dataIndex, $event)
                                    "
                                >
                                    <span class="fa fa-fw fa-arrows"></span>
                                </td>
                                <td
                                    v-for="(
                                        header, headerIndex
                                    ) in lastHeaderRow"
                                    :width="`${
                                        (getHeaderWidthFunc(header.item) /
                                            headerTotalWidth) *
                                        100
                                    }%`"
                                    class="data-cell normal-cell"
                                    :class="[
                                        {
                                            'sticky-left':
                                                fixLeft && headerIndex == 0,
                                            'sticky-right':
                                                fixRight &&
                                                headerIndex ==
                                                    lastHeaderRow.length - 1,
                                        },
                                    ]"
                                    :style="{
                                        left: this.normalSellLeft,
                                    }"
                                >
                                    <slot
                                        :name="`data-${getHeaderNameFunc(
                                            header.item
                                        )}`"
                                        :header="header"
                                        :headerIndex="headerIndex"
                                        :data="data"
                                        :dataIndex="dataIndex"
                                        >{{
                                            data[getHeaderNameFunc(header.item)]
                                        }}</slot
                                    >
                                </td>
                            </tr>
                            <tr
                                v-if="expandable && isItemExpand(data)"
                                class="expand-body-row"
                                :class="[
                                    {
                                        dragging: dataIndex == draggingIndex,
                                        'one-of-us-dragging': draggingIndex != null
                                    },
                                    dataIndex == draggingIndex
                                        ? `c-shadow-${mySize}`
                                        : '',
                                ]"
                            >
                                <td
                                    class="expand-body-cell"
                                    :colspan="`${expandBodyCellColSpan}`"
                                >
                                    <slot
                                        name="expandRow"
                                        :data="data"
                                        :dataIndex="dataIndex"
                                    ></slot>
                                </td>
                            </tr>
                        </template>
                    </tbody>
                </table>
                <slot name="emptyTips" v-if="!dataList.length">
                    <div class="c-p-v-m c-w-100 c-align-center">
                        {{ $t("ATable.Empty") }}
                    </div>
                </slot>
            </div>
        </a-scrollable-h>
    </a-scrollable>
</template>

<style lang="scss" scoped>
@import "../scss/vars";

.a-table {
    table {
        border-collapse: collapse;
        table-layout: fixed;
    }

    thead {
        &.sticky-top {
            position: sticky;
            top: 0;
        }
    }

    tbody tr {
        &.seleced {
            th,
            td:not(.expand-body-cell) {
                background-color: #eaeaea;
            }
        }
        &:not(.seleced) {
            &:nth-child(even) {
                th,
                td:not(.expand-body-cell) {
                    background-color: #fafafa;
                }
            }
            &:hover {
                th,
                td:not(.expand-body-cell) {
                    background-color: #f5f5f5;
                }
            }
        }
        &:not(:last-child) {
            td {
                border-bottom: solid 1px $defaultBorderColor;
            }
        }
        &.one-of-us-dragging:not(.dragging) {
            transition: transform 200ms;
        }
        &.dragging {
            position: relative;
            z-index: 1;
            opacity: 0.8;
        }
    }

    th,
    td {
        background-color: $defaultBgColor;
        text-align: left;
        box-sizing: border-box;

        &.sticky-left {
            position: sticky;
        }

        &.sticky-right {
            position: sticky;
            right: 0;
        }
    }
    th {
        border-bottom: solid 1px $defaultBorderColor;
        &:not(.right-cell) {
            border-right: solid 1px $defaultBorderColor;
        }
    }
    td {
        &:not(:last-child) {
            border-right: solid 1px $defaultBorderColor;
        }
    }

    &.un-top {
        thead {
            &.sticky-top {
                box-shadow: 0 1px 10px $defaultShadowColor;
            }
        }
    }
    &.un-left {
        th,
        td {
            &.sticky-left {
                &::before {
                    content: "";
                    display: block;
                    position: absolute;
                    right: -10px;
                    top: 0;
                    width: 10px;
                    height: 100%;
                    box-shadow: inset 10px 0 10px -10px $defaultShadowColor;
                }
            }
        }
    }
    &.un-right {
        th,
        td {
            &.sticky-right {
                &::before {
                    content: "";
                    display: block;
                    position: absolute;
                    left: -10px;
                    top: 0;
                    width: 10px;
                    height: 100%;
                    box-shadow: inset -10px 0 10px -10px $defaultShadowColor;
                }
            }
        }
    }
    @each $sizePackageName, $sizePackageValue in $sizePackages {
        &.size-#{$sizePackageName} {
            th,
            td:not(.expand-body-cell) {
                padding-left: map-get($sizePackageValue, "space");
                padding-right: map-get($sizePackageValue, "space");
                height: map-get($sizePackageValue, "size");
                font-size: map-get($sizePackageValue, "fontSize");
            }
        }
    }

    .select-cell {
        padding: 0;

        &.selectable {
            text-align: center;
            cursor: pointer;
        }
    }

    .expand-cell {
        padding: 0;

        &.expandable {
            text-align: center;
            cursor: pointer;
        }
    }

    .drag-cell {
        padding: 0;

        &.draggable {
            text-align: center;
            &:not(.disabled) {
                cursor: move;
            }
            &.disabled {
                opacity: 0.5;
                cursor: not-allowed;
            }
        }
    }
}
</style>

<script>
import AScrollable from './AScrollable.vue'
import inputMixin from "../mixins/inputMixin"
import utils from "../common/utils"

export default {
    name: 'ATable',
    components: { AScrollable },
    mixins: [inputMixin],
    emits: ['update:expandValue', 'dragEnd'],
    props: {
        value: {
            type: Array,
            default: []
        },
        headerList: {
            type: Array,
            default: []
        },
        getHeaderNameFunc: {
            type: Function,
            default: a => a.name
        },
        getHeaderTextFunc: {
            type: Function,
            default: a => a.text
        },
        /**
         * 注意不是像素，而是权重
         */
        getHeaderWidthFunc: {
            type: Function,
            default: a => a.width ?? 10
        },
        getSubHeadersFunc: {
            type: Function,
            default: a => a.subHeaders
        },
        dataList: {
            type: Array,
            default: []
        },
        selectable: {
            type: Boolean,
            default: false,
        },
        /**
         * 选择方式，可选multi、single，默认multi，注意，即使为single方式，update:value事件的值也是数组
         */
        selectType: {
            type: String,
            default: 'multi',
        },
        getValueFunc: {
            type: Function,
            default: a => a.id
        },
        getKeyFunc: {
            type: Function,
            default: a => a.id
        },
        maxHeight: {
            type: Number,
            default: null
        },
        getCanBeSelectedFunc: {
            type: Function,
            default: a => true
        },
        tableWidth: {
            type: Number,
            default: null
        },
        fixLeft: {
            type: Boolean,
            default: false,
        },
        fixRight: {
            type: Boolean,
            default: false,
        },
        expandable: {
            type: Boolean,
            default: false,
        },
        /**
         * 展开方式，可选multi、single，默认multi，注意，即使为single方式，update:expandValue事件的值也是数组
         */
        expandType: {
            type: String,
            default: 'multi',
        },
        expandValue: {
            type: Array,
            default: []
        },
        draggable: {
            type: Boolean,
            default: false,
        },
    },
    data() {
        return {
            actionWidth: 60,
            scrollDistanceTop: 0,
            scrollDistanceRight: 0,
            scrollDistanceBottom: 0,
            scrollDistanceLeft: 0,
            draggingIndex: null,
            startMouseY: null,
            startTranslateY: null,
            lastMoveOnIndex: null,
        }
    },
    computed: {
        valueSet() {
            return new Set(this.value)
        },
        anySelected() {
            return this.dataList.some(a => this.valueSet.has(this.getValueFunc(a)))
        },
        allSelected() {
            return this.dataList.every(a => this.valueSet.has(this.getValueFunc(a)))
        },
        isMultiSelect() {
            return this.selectType == 'multi'
        },
        tableContainerStyle() {
            if (this.maxHeight > 0) {
                return {
                    maxHeight: this.maxHeight + 'px',
                }
            }
            return {}
        },
        tableStyle() {
            if (this.tableWidth) {
                return {
                    width: this.tableWidth + 'px'
                }
            }
            return {
                width: '100%'
            }
        },
        headerInfo() {
            let totalWidth = 0

            let getColSpan = (header) => {
                let subHeaders = this.getSubHeadersFunc(header)
                if (subHeaders == null || subHeaders.length == 0) {
                    return 1
                }
                return subHeaders.reduce((total, a) => total + getColSpan(a), 0)
            }
            let root = {
                parent: null,
                item: {
                    subHeaders: [...this.headerList]
                },
                subItemList: [],
                rowSpan: 1,
                colSpan: 1,
            }
            let sourceItemList = [root]
            let rows = []
            let firstItem = root
            let lastItem = root
            let lastHeaderRow = []
            while (true) {
                let currentItem = sourceItemList.shift()

                currentItem.colSpan = getColSpan(currentItem.item)

                let subHeaders = this.getSubHeadersFunc(currentItem.item)
                if (subHeaders?.length ?? 0 > 0) {
                    let subItemList = subHeaders.map(a => {
                        return {
                            parent: currentItem,
                            item: a,
                            subItemList: [],
                            rowSpan: 1,
                            colSpan: 1,
                        }
                    })
                    currentItem.subItemList = subItemList
                    sourceItemList.push(...subItemList)
                } else {
                    totalWidth += this.getHeaderWidthFunc(currentItem.item)
                    lastHeaderRow.push(currentItem)
                }

                if (currentItem == firstItem) {
                    rows.forEach(row => {
                        row.forEach(a => {
                            if (a.subItemList.length == 0) {
                                a.rowSpan++
                            }
                        })
                    })
                    rows.push([])
                }

                rows[rows.length - 1].push(currentItem)

                if (sourceItemList.length == 0) {
                    break
                }

                if (currentItem == lastItem) {
                    firstItem = sourceItemList[0]
                    lastItem = sourceItemList[sourceItemList.length - 1]
                }
            }
            rows.shift()

            let leftHeaderList = []
            let leftParentHeader = this.headerList[0]
            while (true) {
                leftHeaderList.push(leftParentHeader)
                let subHeaders = this.getSubHeadersFunc(leftParentHeader)
                if (subHeaders == null || subHeaders.length == 0) {
                    break
                }
                leftParentHeader = subHeaders[subHeaders[0]]
            }

            let rightHeaderList = []
            let rightParentHeader = this.headerList[this.headerList.length - 1]
            while (true) {
                rightHeaderList.push(rightParentHeader)
                let subHeaders = this.getSubHeadersFunc(rightParentHeader)
                if (subHeaders == null || subHeaders.length == 0) {
                    break
                }
                rightParentHeader = subHeaders[subHeaders.length - 1]
            }

            return {
                rows,
                totalWidth,
                lastHeaderRow,
                leftHeaderList,
                rightHeaderList
            }
        },
        headerTotalWidth() {
            return this.headerInfo.totalWidth
        },
        headerRows() {
            return this.headerInfo.rows
        },
        firstHeaderRow() {
            return this.headerInfo.rows[0]
        },
        restHeaderRows() {
            return this.headerInfo.rows.slice(1)
        },
        lastHeaderRow() {
            return this.headerInfo.lastHeaderRow
        },
        leftHeaderList() {
            return this.headerInfo.leftHeaderList
        },
        leftHeaderSet() {
            return new Set(this.leftHeaderList)
        },
        rightHeaderList() {
            return this.headerInfo.rightHeaderList
        },
        rightHeaderSet() {
            return new Set(this.rightHeaderList)
        },
        expandValueSet() {
            return new Set(this.expandValue)
        },
        anyExpand() {
            return this.dataList.some(a => this.expandValueSet.has(this.getValueFunc(a)))
        },
        allExpand() {
            return this.dataList.every(a => this.expandValueSet.has(this.getValueFunc(a)))
        },
        isMultiExpand() {
            return this.expandType == 'multi'
        },
        expandBodyCellColSpan() {
            let n = this.lastHeaderRow.length
            if (this.selectable) {
                n += 1
            }
            if (this.expandable) {
                n += 1
            }
            if (this.draggable) {
                n += 1
            }
            return n
        },
        selectCellLeft() {
            return 0
        },
        expandCellLeft() {
            let n = 0
            if (this.selectable) {
                n += 1
            }
            return n * this.actionWidth + 'px'
        },
        dragCellLeft() {
            let n = 0
            if (this.selectable) {
                n += 1
            }
            if (this.expandable) {
                n += 1
            }
            return n * this.actionWidth + 'px'
        },
        normalSellLeft() {
            let n = 0
            if (this.selectable) {
                n += 1
            }
            if (this.expandable) {
                n += 1
            }
            if (this.draggable) {
                n += 1
            }
            return n * this.actionWidth + 'px'
        },
    },
    watch: {
        async dataList(){
          await this.$nextTick()
          Array.from(this.$refs.table.querySelectorAll(':scope > tbody > tr')).forEach(a => a.style.transform = '')
        },
    },
    mounted() {
        this.calcScrollDistance()
        let containerEl = utils.getEl(this.$el)
        containerEl.addEventListener('scroll', this.calcScrollDistance)
        window.document.addEventListener('mouseup', this.onDocumentMouseup)
        window.document.addEventListener('mousemove', this.onDocumentMousemove)
    },
    unmounted() {
        window.document.removeEventListener('mouseup', this.onDocumentMouseup)
        window.document.removeEventListener('mousemove', this.onDocumentMousemove)
    },
    methods: {
        input(val) {
            this.$emit('update:value', val)
        },
        isItemSelected(item) {
            let itemValue = this.getValueFunc(item)
            return this.valueSet.has(itemValue)
        },
        toggleSelectItem(item) {
            let itemValue = this.getValueFunc(item)
            if (this.isMultiSelect) {
                if (!this.isItemSelected(item)) {
                    this.input([...this.value, itemValue])
                } else {
                    this.input(this.value.filter(a => a != itemValue))
                }
            } else {
                this.input([itemValue])
            }
        },
        toggleSelectAll() {
            if (this.anySelected) {
                let dataListValueSet = new Set(this.dataList.map(a => this.getValueFunc(a)))
                this.input(this.value.filter(a => !dataListValueSet.has(a)))
            } else {
                let newValue = [...this.value]
                this.dataList.forEach(a => {
                    if (this.getCanBeSelectedFunc(a)) {
                        let value = this.getValueFunc(a)
                        if (!this.valueSet.has(value)) {
                            newValue.push(value)
                        }
                    }
                })
                this.input(newValue)
            }
        },
        calcScrollDistance() {
            let containerEl = utils.getEl(this.$el)
            this.scrollDistanceTop = containerEl.scrollTop
            this.scrollDistanceRight = containerEl.scrollWidth - containerEl.clientWidth - containerEl.scrollLeft
            this.scrollDistanceBottom = containerEl.scrollHeight - containerEl.clientHeight - containerEl.scrollTop
            this.scrollDistanceLeft = containerEl.scrollLeft
        },
        inputExpand(val) {
            this.$emit('update:expandValue', val)
        },
        isItemExpand(item) {
            let itemValue = this.getValueFunc(item)
            return this.expandValueSet.has(itemValue)
        },
        toggleExpandItem(item) {
            let itemValue = this.getValueFunc(item)
            if (this.isMultiExpand) {
                if (!this.isItemExpand(item)) {
                    this.inputExpand([...this.expandValue, itemValue])
                } else {
                    this.inputExpand(this.expandValue.filter(a => a != itemValue))
                }
            } else {
                if (!this.isItemExpand(item)) {
                    this.inputExpand([itemValue])
                } else {
                    this.inputExpand([])
                }
            }
        },
        toggleExpandAll() {
            if (this.anyExpand) {
                let dataListValueSet = new Set(this.dataList.map(a => this.getValueFunc(a)))
                this.inputExpand(this.expandValue.filter(a => !dataListValueSet.has(a)))
            } else {
                let newValue = [...this.expandValue]
                this.dataList.forEach(a => {
                    let value = this.getValueFunc(a)
                    if (!this.expandValueSet.has(value)) {
                        newValue.push(value)
                    }
                })
                this.inputExpand(newValue)
            }
        },
        getTranslateY(el) {
            return el.style.transform?.match(/-?\d+/) * 1 ?? 0
        },
        dragStart(dataIndex, e) {
            this.startMouseY = e.clientY
            this.draggingIndex = dataIndex
            this.trList = Array.from(this.$refs.table.querySelectorAll(':scope > tbody > tr.data-row')).map(a => {
                let dataRowRect = a.getBoundingClientRect()
                let obj = {
                    dataRowEl: a,
                    rect: {
                        top: dataRowRect.top,
                        bottom: dataRowRect.bottom,
                        height: dataRowRect.height
                    }
                }
                let expandBodyRowEl = a.nextElementSibling
                if (expandBodyRowEl && expandBodyRowEl.classList.contains('expand-body-row')) {
                    obj.expandBodyRowEl = expandBodyRowEl
                    let expandBodyRowRect = expandBodyRowEl.getBoundingClientRect()
                    obj.rect.height += expandBodyRowRect.height
                    obj.rect.bottom = expandBodyRowRect.bottom
                }
                return obj
            })
            let draggingTrEl = this.trList[this.draggingIndex].dataRowEl
            this.startTranslateY = this.getTranslateY(draggingTrEl)
        },
        onDocumentMousemove(e) {
            if (this.draggingIndex == null) {
                return
            }
            let draggingTrEl = this.trList[this.draggingIndex].dataRowEl
            draggingTrEl.style.transform = `translateY(${e.clientY - this.startMouseY + this.startTranslateY}px)`
            let draggingExpandBodyRowEl = this.trList[this.draggingIndex].expandBodyRowEl
            if (draggingExpandBodyRowEl) {
                draggingExpandBodyRowEl.style.transform = `translateY(${e.clientY - this.startMouseY + this.startTranslateY}px)`
            }
            let moveOnIndex = this.trList.findIndex(a => a.rect.top <= e.clientY && a.rect.bottom >= e.clientY)
            let lastMoveOnIndex = this.lastMoveOnIndex
            this.lastMoveOnIndex = moveOnIndex
            if (moveOnIndex == -1 || moveOnIndex == this.draggingIndex || moveOnIndex == lastMoveOnIndex) {
                return
            }
            let moveOnTrEl = this.trList[moveOnIndex].dataRowEl
            let draggingRect = this.trList[this.draggingIndex].rect
            let moveOnRect = this.trList[moveOnIndex].rect

            let oldMoveOnRectTop = moveOnRect.top
            if (draggingRect.top > moveOnRect.top) {
                let oldDraggingRectBottom = draggingRect.bottom
                draggingRect.top = moveOnRect.top
                draggingRect.bottom = draggingRect.top + draggingRect.height
                moveOnRect.bottom = oldDraggingRectBottom
                moveOnRect.top = moveOnRect.bottom - moveOnRect.height
            } else {
                let oldMoveOnRectBottom = moveOnRect.bottom
                moveOnRect.top = draggingRect.top
                moveOnRect.bottom = moveOnRect.top + moveOnRect.height
                draggingRect.bottom = oldMoveOnRectBottom
                draggingRect.top = draggingRect.bottom - draggingRect.height
            }
            let oldTranslateY = this.getTranslateY(moveOnTrEl)
            let newTranslateY = moveOnRect.top - oldMoveOnRectTop + oldTranslateY
            moveOnTrEl.style.transform = `translateY(${newTranslateY}px)`
            let moveOnExpandBodyRowEl = this.trList[moveOnIndex].expandBodyRowEl
            if (moveOnExpandBodyRowEl) {
                moveOnExpandBodyRowEl.style.transform = `translateY(${newTranslateY}px)`
            }
        },
        onDocumentMouseup() {
            if (this.draggingIndex == null) {
                return
            }
            let draggingTrEl = this.trList[this.draggingIndex].dataRowEl
            let draggingRect = this.trList[this.draggingIndex].rect
            let realRect = draggingTrEl.getBoundingClientRect()
            let oldTranslateY = this.getTranslateY(draggingTrEl)
            let newTranslateY = draggingRect.top - realRect.top + oldTranslateY
            draggingTrEl.style.transform = `translateY(${newTranslateY}px)`
            let draggingExpandBodyRowEl = this.trList[this.draggingIndex].expandBodyRowEl
            if (draggingExpandBodyRowEl) {
                draggingExpandBodyRowEl.style.transform = `translateY(${newTranslateY}px)`
            }
            let listToResort = this.trList.map((a, i) => {
                return {
                    index: i,
                    rect: a.rect
                }
            })
            listToResort.sort((a, b) => a.rect.top - b.rect.top)
            let newDataList = listToResort.map(a => this.dataList[a.index])

            this.draggingIndex = null
            this.startMouseY = null
            this.lastMoveOnIndex = null
            this.trList = []
            
            this.$emit('dragEnd', newDataList)
        },
    },
}
</script>